
#include "DuplicatePart.h"
#include "Duplicate/DuplicateMgr.h"
#include "drop/DropMgr.h"
#include "Common/TableData/ConstantConstantCfg.h"
#include "Character/monster/MonsterRefCfg.h"
#include "Common/TableData/AreaAreaCfg.h"
#include "Common/TableDataEx/DuplicateCfg.h"
#include "Global/LGlobalMgr.h"
#include "Common/MailDefine.h"
#include "Mail/GMailManager.h"
#include "base/core/Utf8AndWideChar.h"
#include "Common/TableData/ActivityDailyCfg.h"
#include "Common/ActivityDefine.h"
#include "Character/OperateLimitPart.h"
#include "Common/Utility/TimeUtility.h"
#include "Scene/MapMgr.h"
#include "Character/HuoYueDuPart.h"
#include "ServerModule/LogicActivityModule.h"
DuplicatePart::DuplicatePart()
{
	m_setOpenDup.clear();
	m_historyLayer = 0;
	m_curLayer = 0;
	m_lastLayerTime = 0;
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_INFO, &DuplicatePart::Info));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_ENTER, &DuplicatePart::Enter));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_LEAVE, &DuplicatePart::Leave));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_RELIVE, &DuplicatePart::Relive));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_ENTER_AREA, &DuplicatePart::EnterArea));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_INVITE_ENTER, &DuplicatePart::InviteEnter));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_REPLY_INVITE, &DuplicatePart::ReplyInvite));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_START_CHALLENGE, &DuplicatePart::StartChallenge));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_JOIN_QUEUE, &DuplicatePart::JoinQueue));
	m_mapMsgfunc.insert(std::make_pair(CLIENT_TO_LOGIC_DUPLICATE_DROP_DATA, &DuplicatePart::DropData));
	
}

DuplicatePart::~DuplicatePart()
{

}


bool DuplicatePart::Init(Creature *pMaster, uint32_t partType, CharacterDBInfo* pCharacterDB /*= nullptr*/)
{
	Part::Init(pMaster, partType);
	//
	m_mapDuplicate.clear();
	m_setOpenDup.clear();
	m_mapGroup.clear();
	m_setAllDuplicate.clear();
	m_historyLayer = 0;
	m_curLayer = 0;
	m_lastLayerTime = 0;

	if (nullptr != pCharacterDB)
	{
		if (pCharacterDB->has_duplicatedata())
		{
			const CharacterDBDuplicateData &protoDBDuplicate = pCharacterDB->duplicatedata();

			//副本
			int32_t nsize = protoDBDuplicate.duplicate_size();
			for (int32_t i = 0; i < nsize; ++i)
			{
				const DuplicateSingleProto &single = protoDBDuplicate.duplicate(i);
				const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(single.dupliate_id());
				if (nullptr != pcfg)
				{
					m_setAllDuplicate.insert(single.dupliate_id());
					SDuplicate stLevel;
					stLevel.nDuplicateID = single.dupliate_id();
					m_mapDuplicate[stLevel.nDuplicateID] = stLevel;

				}
			}
			//副本组
			nsize = protoDBDuplicate.group_size();
			for (int32_t j = 0; j < nsize; ++j)
			{
				const DuplicateGroupProto &group = protoDBDuplicate.group(j);
				const DuplicateGroupCfgInfo *pcfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(group.group_id());
				if (nullptr != pcfg)
				{
					SDuplicateGroup stGroup;
					stGroup.groupId = group.group_id();
					if (group.has_enter_num())
					{
						stGroup.enterNum = group.enter_num();
					}
					if (group.has_use_item_num())
					{
						stGroup.useItemNum = group.use_item_num();
					}
					if (group.has_last_fresh())
					{
						stGroup.lastFresh = group.last_fresh();
					}
					//LogDebugFmtPrint("DuplicatePart::Init....groupid:%u, enternum:%d, usenum:%d, lastfresh:%lu ", stGroup.groupId, stGroup.enterNum, stGroup.useItemNum, stGroup.lastFresh);
					m_mapGroup[stGroup.groupId] = stGroup;
				}
			}

			//开启副本
			nsize = protoDBDuplicate.open_dup_size();
			for (int32_t k = 0; k < nsize; ++k)
			{
				m_setOpenDup.insert(protoDBDuplicate.open_dup(k));
			}

			//天梯副本历史层数
			if (protoDBDuplicate.has_ladder())
			{
				const DuplicateLadderExProto &ladderProto = protoDBDuplicate.ladder();
				m_historyLayer = ladderProto.history_layer();
				m_curLayer = ladderProto.cur_layer();
				m_lastLayerTime = ladderProto.last_time();
			}
		}
	}
	//检查副本组次数刷新
	CheckDupGroup();
	//订阅任务完成事件
	g_GetEvent()->Subscribe(this, EVENT_FINISH_TASK, m_pMaster->GetCid(), CREATURE_PLAYER, "DuplicatePart::Init");


	return true;
}

bool DuplicatePart::UnInit()
{
	g_GetEvent()->UnSubscribeAll(this);

	m_setAllDuplicate.clear();
	m_setOpenDup.clear();
	m_mapDuplicate.clear();
	m_mapGroup.clear();
	m_mapMsgfunc.clear();
	m_historyLayer = 0;
	m_curLayer = 0;
	m_lastLayerTime = 0;
	return true;
}

bool DuplicatePart::OnMsgHandle(uint32_t cmd, const char* data, uint32_t len)
{
	mapMsgFunc::iterator iter = m_mapMsgfunc.find(cmd);
	if (iter == m_mapMsgfunc.end())
		LogErrFmtPrint("msg dont exit in DuplicatePart, cmd:%d", cmd);
	else
		(this->*m_mapMsgfunc[cmd])(data, len);

	return true;
}

void DuplicatePart::OnExecute(uint16_t nEventID, uint64_t nSrcID, uint8_t bySrcType, void *pContext, int32_t nLen)
{
	switch (nEventID)
	{
	case EVENT_FINISH_TASK:
		{
			if (nLen != sizeof(FinishTaskEvent))
			{
				LogErrFmtPrint("[logic] DuplicatePart::OnExecute....nLen != sizeof(FinishTaskEvent)....len:%d ", nLen);
				return;
			}
			SET_UINT32 setAdd;
			setAdd.clear();
			FinishTaskEvent *pEvent = (FinishTaskEvent*)pContext;
			const SET_UINT32 *punlockDup = g_GetDuplicateCfgMgr()->GetUnlockDupByTaskId((int8_t)m_pMaster->GetAttr(C_RACE),pEvent->taskId);
			if (nullptr != punlockDup)
			{
				SET_UINT32::const_iterator iter = punlockDup->begin();
				for (; iter != punlockDup->end(); ++iter)
				{
					uint32_t dupId = (*iter);

					//是否已开启
					SET_UINT32::iterator iterOpen = m_setOpenDup.find(dupId);
					if (iterOpen == m_setOpenDup.end())
					{
						//是否已通关
						DuplicateMap::iterator iterDup = m_mapDuplicate.find(dupId);
						if (iterDup == m_mapDuplicate.end())
						{
							m_setOpenDup.insert(dupId);
							setAdd.insert(dupId);
						}
					}				

				}
				//
				UpdateDupOpen(setAdd);
			}
		}
		break;
	default:
		break;
	}

}

void DuplicatePart::OnTimer(uint32_t nTimerID)
{

}

bool DuplicatePart::SynClient(PlayerClientInfo& playerInfo)
{
	return true;
}

bool DuplicatePart::SaveDB(CharacterDBInfo& characterDB)
{
	CharacterDBDuplicateData *protoDBDuplicate = characterDB.mutable_duplicatedata();
	if (nullptr != protoDBDuplicate)
	{
		DuplicateMap::iterator iterLevel = m_mapDuplicate.begin();
		for (; iterLevel != m_mapDuplicate.end(); ++iterLevel)
		{
			SDuplicate &stLevel = iterLevel->second;
			DuplicateSingleProto *protoSingle = protoDBDuplicate->add_duplicate();
			if (nullptr != protoSingle)
			{
				protoSingle->set_dupliate_id(stLevel.nDuplicateID);
			}
		}

		DuplicateGroupMap::iterator iterGroup = m_mapGroup.begin();
		for (; iterGroup != m_mapGroup.end(); ++iterGroup)
		{
			SDuplicateGroup &stGroup = iterGroup->second;
			DuplicateGroupProto *protoGroup = protoDBDuplicate->add_group();
			if (nullptr != protoGroup)
			{
				protoGroup->set_group_id(stGroup.groupId);
				protoGroup->set_enter_num(stGroup.enterNum);
				protoGroup->set_use_item_num(stGroup.useItemNum);
				protoGroup->set_last_fresh(stGroup.lastFresh);

				//LogDebugFmtPrint("DuplicatePart::SaveDB....groupid:%u, enternum:%d, usenum:%d, lastfresh:%lu ", stGroup.groupId, stGroup.enterNum, stGroup.useItemNum, stGroup.lastFresh);
			}
		}

		SET_UINT32::iterator iterOpen = m_setOpenDup.begin();
		for (; iterOpen != m_setOpenDup.end(); ++iterOpen)
		{
			protoDBDuplicate->add_open_dup((*iterOpen));
		}


		DuplicateLadderExProto *protoLadder = protoDBDuplicate->mutable_ladder();
		if (nullptr != protoLadder)
		{
			protoLadder->set_history_layer(m_historyLayer);
			protoLadder->set_cur_layer(m_curLayer);
			protoLadder->set_last_time(m_lastLayerTime);
		}
		
	}
	
	return true;
}

bool DuplicatePart::DailyUpdate(uint64_t unixSec)
{
	Duplicate_UpdateRsp protoUpdate;
	uint64_t curTime = g_GetGlobalServerTime()->UnixSec();
	DuplicateGroupMap::iterator iterGroup = m_mapGroup.begin();
	for (; iterGroup != m_mapGroup.end(); ++iterGroup)
	{
		SDuplicateGroup &stGroup = iterGroup->second;
		const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(stGroup.groupId);
		if (nullptr != pGroupCfg && EDupFreshType_Day == pGroupCfg->refreshType)
		{
			stGroup.enterNum = 0;
			stGroup.useItemNum = 0;
			stGroup.lastFresh = curTime;
			//
			DuplicateGroupProto *proto = protoUpdate.add_group();
			if (nullptr != proto)
			{
				proto->set_group_id(stGroup.groupId);
				proto->set_enter_num(stGroup.enterNum);
				proto->set_use_item_num(stGroup.useItemNum);
				proto->set_last_fresh(stGroup.lastFresh);
			}
		}
	}

	UpdateDuplicate(protoUpdate);

	//天梯层数重置
	m_curLayer = 0;
	m_lastLayerTime = g_GetGlobalServerTime()->UnixSec();
	//
	const ConstantConstantCfgInfo *pConstCfg = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg_LadderDupResetCount);
	if (nullptr != pConstCfg)
	{
		m_curLayer = (pConstCfg->constantdata > m_historyLayer) ? 0 : (m_historyLayer - pConstCfg->constantdata);
		m_curLayer = (m_curLayer >= 1) ? (m_curLayer - 1) : 0;
	}
	UpdateLadder();

	return true;
}

bool DuplicatePart::WeekUpdate(uint64_t unixSec)
{
	uint64_t curTime = g_GetGlobalServerTime()->UnixSec();
	Duplicate_UpdateRsp protoUpdate;
	DuplicateGroupMap::iterator iterGroup = m_mapGroup.begin();
	for (; iterGroup != m_mapGroup.end(); ++iterGroup)
	{
		SDuplicateGroup &stGroup = iterGroup->second;
		const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(stGroup.groupId);
		if (nullptr != pGroupCfg && EDupFreshType_Week == pGroupCfg->refreshType)
		{
			stGroup.enterNum = 0;
			stGroup.useItemNum = 0;
			stGroup.lastFresh = curTime;
			//
			DuplicateGroupProto *protoGroup = protoUpdate.add_group();
			if (nullptr != protoGroup)
			{
				protoGroup->set_group_id(stGroup.groupId);
				protoGroup->set_enter_num(stGroup.enterNum);
				protoGroup->set_use_item_num(stGroup.useItemNum);
				protoGroup->set_last_fresh(stGroup.lastFresh);
			}
		}
	}
	UpdateDuplicate(protoUpdate);

	return true;
}

//通知离开副本
void DuplicatePart::NotifyLeave(uint32_t nDuplicateID,int8_t byKeyType)
{
	LogDebugFmtPrint("[logic]  DuplicatePart::NotifyLeave ..dupid:%u, type:%d , cid:%lu ", nDuplicateID, byKeyType, m_pMaster->GetCid());
	//设置副本ID为0
	m_pMaster->SetAttr(C_DUPLICATE_ID, 0);
	//
	//玩家离开副本有消息到中心服，离开副本房间的处理在中心服已经处理这里不再处理

	Duplicate_LeaveRsp rsp;
	rsp.set_retcode(RET_SUCCESS);
	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_LEAVE, &rsp);
}

//准备进入副本
int32_t DuplicatePart::PrepareEnter(uint32_t duplicateId, uint32_t sceneId, int8_t keyType, uint64_t keyValue)
{
	int32_t ret = RET_FAIL;
	CharIDType cid = m_pMaster->GetCid();
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(duplicateId);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::PrepareEnter ... nullptr == pCfg...nDuplicateID:%u, cid:%lu ", duplicateId, cid);
	}
	else
	{
		const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pCfg->groupID);
		if (nullptr == pGroupCfg)
		{
			LogErrFmtPrint("[logic] DuplicatePart::PrepareEnter ... nullptr == pGroupCfg...groupID:%u,cid:%lu ", pCfg->groupID, cid);
		}
		else
		{
			ret = CanEnter(keyType, keyValue, pCfg, pGroupCfg);
		}
	}

	return ret;
}
//通知进入副本
bool DuplicatePart::NotifyEnter(uint32_t duplicateId, uint32_t sceneId, uint32_t bornId /*= 0*/)
{
	//切换到副本场景
	CharIDType cid = m_pMaster->GetCid();
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(duplicateId);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnter ... nullptr == pCfg...nDuplicateID:%u, sceneid:%u, cid:%lu ", duplicateId, sceneId, cid);
		return false;
	}

	const BornRefLocation *pBornCfg = g_GetMapLocationCfg()->RandBornLocation(pCfg->sceneResource);
	if (nullptr == pBornCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnter ... nullptr == pBornCfg...nDuplicateID:%u, sceneid:%u,mapid:%u, cid:%lu ", duplicateId, sceneId, pCfg->sceneResource, cid);
		return false;
	}
	Player *pPlayer = static_cast<Player*>(m_pMaster);
	if (pPlayer == nullptr)
	{
		//不在线
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnter ... plyaer not in ACCOUNT_GAME_STATE_GAMING state...nDuplicateID:%u, sceneid:%u,mapid:%u, cid:%lu ", duplicateId, sceneId, pCfg->sceneResource, cid);
		return false;
	}
	//
	if (pPlayer->IsDead())
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnter ... plyaer is dead...nDuplicateID:%u, sceneid:%u,mapid:%u, cid:%lu ", duplicateId, sceneId, pCfg->sceneResource, cid);
		return false;
	}

	Point3<float> pos = pBornCfg->m_pos;	
	if ((int8_t)EDuplicateType::EDuplicateType_Arena == pCfg->duplicateType || (int8_t)EDuplicateType::EDuplicateType_Camp == pCfg->duplicateType)
	{
		//竞技场副本玩家取第一个出生点坐标
		const BornRefLocation *pBornCfgEx = g_GetMapLocationCfg()->GetBornLocationByIdx(pCfg->sceneResource,0);
		if (nullptr != pBornCfgEx)
		{
			pos = pBornCfgEx->m_pos;
		}
		else
		{
			LogDebugFmtPrint("[logic] DuplicatePart::NotifyEnter 11....nullptr == pBornCfgEx charid:%lu, dupid:%u, duptype:%d, sceneid:%u, bornid:%d [%f,%f,%f] ", cid, duplicateId, pCfg->duplicateType, sceneId, bornId, pos.x, pos.y, pos.z);
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Compete == pCfg->duplicateType)
	{
		const BornRefLocation *pBornCfgEx = g_GetMapLocationCfg()->GetBornLocationByIdx(pCfg->sceneResource, bornId);
		if (nullptr != pBornCfgEx)
		{
			pos = pBornCfgEx->m_pos;
		}
		else
		{
			LogDebugFmtPrint("[logic] DuplicatePart::NotifyEnter compete....nullptr == pBornCfgEx charid:%lu, dupid:%u, duptype:%d, sceneid:%u, bornid:%d [%f,%f,%f] ", cid, duplicateId, pCfg->duplicateType, sceneId, bornId, pos.x, pos.y, pos.z);
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Pestilence == pCfg->duplicateType)
	{
		//瘟疫之战副本
		const BornRefLocation *pBornCfgEx = g_GetMapLocationCfg()->GetMapBornLocation(pCfg->sceneResource, bornId);
		if (nullptr != pBornCfgEx)
		{
			pos = pBornCfgEx->m_pos;
		}
		else
		{
			LogDebugFmtPrint("[logic] DuplicatePart::NotifyEnter. 22 ... pestilence dup... nullptr == pBornCfgEx   charid:%lu, dupid:%u, duptype:%d, sceneid:%u, mapid:%u, bornid:%d [%f,%f,%f] ", cid, duplicateId, pCfg->duplicateType, sceneId,pCfg->sceneResource, bornId, pos.x, pos.y, pos.z);
			return false;
		}
	}
	STransParam transParam;
	transParam.srcMapId = m_pMaster->GetMapId();
	transParam.transType = ETransType_Dup;
	transParam.dupId = pCfg->duplicateID;
	if (!pPlayer->TransScene(sceneId, pos, pCfg->sceneResource, transParam))
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnter ... m_pMaster->TransScene failed...nDuplicateID:%u, sceneid:%u,mapid:%u, cid:%lu ", duplicateId, sceneId, pCfg->sceneResource, cid);
		return false;
	}
	LogDebugFmtPrint("[logic] DuplicatePart::NotifyEnter.... charid:%lu, dupid:%u, duptype:%d, sceneid:%u, bornid:%d [%f,%f,%f] ", cid, duplicateId, pCfg->duplicateType, sceneId, bornId, pos.x, pos.y, pos.z);

	return true;
}
//通知进入失败
void DuplicatePart::NotifyEnterFailed(uint32_t nDuplicateID, int32_t retcode)
{
	Duplicate_EnterRsp rsp;
	rsp.set_retcode(retcode);
	rsp.set_duplicate_id(nDuplicateID);
	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
}
//通知进入成功
void DuplicatePart::NotifyEnterSuccess(DupEnterParam &enterParam)
{
	CharIDType cid = m_pMaster->GetCid();
	uint32_t nDuplicateID = enterParam.dupId;
	uint32_t nSceneID = enterParam.sceneId;

	//设置副本ID
	Point3<float> pos = m_pMaster->GetPos();
	LogDebugFmtPrint("[logic] DuplicatePart::NotifyEnterSuccess.... charid:%lu, dupid:%u, sceneid:%u , %u , [%f,%f,%f]", cid, nDuplicateID, nSceneID, m_pMaster->GetAttr(C_DUPLICATE_ID), pos.x, pos.y, pos.z);
	//
	if (!g_GetSceneMgr()->GetScene(nSceneID))
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnterSuccess...can not find scene ....cid:%lu, dupid:%u, nSceneID:%u ", cid, nDuplicateID, nSceneID);
	}
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(nSceneID);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("[logic] DuplicatePart::NotifyEnterSuccess...can not find duplicate ....cid:%lu, dupid:%u, nSceneID:%u ", cid, nDuplicateID, nSceneID);
		return;
	}
	if ((int8_t)EDuplicateType::EDuplicateType_UnionHome != pDuplicate->GetType()
		&& (int8_t)EDuplicateType::EDuplicateType_DunGeon != pDuplicate->GetType()
		) //工会驻地和工会地宫 只是一个动态场景，不用设置副本ID
	{
		m_pMaster->SetAttr(C_DUPLICATE_ID, nDuplicateID);
	}
	Duplicate_UpdateRsp protoUpdate;
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(nDuplicateID);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::PrepareEnter ... nullptr == pCfg...nDuplicateID:%u, cid:%lu ", nDuplicateID, cid);
	}
	else
	{
		//活动相关的副本需要记录活动次数
		PLAYER_ROLE_STATIS_TYPE_E opType = PRSTE_TEST;
		if ((int8_t)EDuplicateType::EDuplicateType_Pestilence == pCfg->duplicateType)
		{
			opType = PRSTE_PESTILENCE;
		}
		else if ((int8_t)EDuplicateType::EDuplicateType_Tower == pCfg->duplicateType)
		{
			opType = PRSTE_TOWER;
		}
		else if ((int8_t)EDuplicateType::EDuplicateType_Guard == pCfg->duplicateType)
		{
			opType = PRSTE_GUARD;
		}
		else if ((int8_t)EDuplicateType::EDuplicateType_Cloud == pCfg->duplicateType)
		{
			opType = PRSTE_CLOUD;
		}

		

		if (opType != PRSTE_TEST && !pDuplicate->OnceEnter(cid))
		{
			//瘟疫之战活动副本，扣除活动次数
			OperateLimitPart *pPart = dynamic_cast<OperateLimitPart*>(m_pMaster->GetPart(PART_OPERATELIMIT));
			if (nullptr != pPart)
			{
				if (opType != PRSTE_TEST)
				{
					pPart->AddOprateLimit(opType, 1);
				}
			}
		}

		int32_t huoyue = 0;
		if (EDuplicateGroup_RoberNest == pCfg->groupID)
		{
			huoyue = HYDT_ACTIVITY_NEST;
		}
		else if (EDuplicateGroup_EverSpring == pCfg->groupID)
		{
			huoyue = HYDT_ACTIVITY_SPRING;
		}

		if (huoyue > 0)
		{
			HuoYueDuPart *pHuoyue = dynamic_cast<HuoYueDuPart*>(m_pMaster->GetPart(PART_HUOYUEDU));
			if (nullptr != pHuoyue)
			{
				pHuoyue->AddHuoYueDuRecord(huoyue);
			}
		}

		//更新副本数据
		const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pCfg->groupID);
		if (nullptr != pGroupCfg)
		{
			bool useItemFlag = false;//是否用物品进入的标记
			//是否曾经进入过该副本
			if (!pDuplicate->OnceEnter(cid))
			{
				uint64_t curTime = g_GetGlobalServerTime()->UnixSec();
				//扣除次数
				SDuplicateGroup *pGroup = GetGroup(pGroupCfg->id);
				if (DUP_INFINITE_ENTER_NUM != pGroupCfg->groupTimes)
				{
					if (nullptr != pGroup)
					{
						if (pGroup->enterNum < pGroupCfg->groupTimes)
						{
							//免费次数
							pGroup->enterNum += 1;
						}
						else
						{
							//使用物品次数
							pGroup->useItemNum += 1;
							useItemFlag = true;
						}
						pGroup->lastFresh = curTime;

						DuplicateGroupProto *protoGroup = protoUpdate.add_group();
						if (nullptr != protoGroup)
						{
							protoGroup->set_group_id(pGroup->groupId);
							protoGroup->set_enter_num(pGroup->enterNum);
							protoGroup->set_use_item_num(pGroup->useItemNum);
							protoGroup->set_last_fresh(pGroup->lastFresh);
						}
						//LogDebugFmtPrint("DuplicatePart::EnterSucess....groupid:%u, enternum:%d, usenum:%d, lastfresh:%lu ", pGroup->groupId, pGroup->enterNum, pGroup->useItemNum, pGroup->lastFresh);
					}
					else
					{
						SDuplicateGroup stGroup;
						stGroup.groupId = pGroupCfg->id;
						stGroup.lastFresh = curTime;
						if (pGroupCfg->groupTimes > 0 )
						{
							stGroup.enterNum += 1;
						}
						else
						{
							//进入次数为0，需要用道具进入
							stGroup.useItemNum += 1;
							useItemFlag = true;
						}
						m_mapGroup[stGroup.groupId] = stGroup;
						//
						DuplicateGroupProto *protoGroup = protoUpdate.add_group();
						if (nullptr != protoGroup)
						{
							protoGroup->set_group_id(stGroup.groupId);
							protoGroup->set_enter_num(stGroup.enterNum);
							protoGroup->set_use_item_num(stGroup.useItemNum);
							protoGroup->set_last_fresh(stGroup.lastFresh);
						}
						//LogDebugFmtPrint("DuplicatePart::EnterSucess 11....groupid:%u, enternum:%d, usenum:%d, lastfresh:%lu ", stGroup.groupId, stGroup.enterNum, stGroup.useItemNum, stGroup.lastFresh);
					}

					if (useItemFlag)//使用物品进入，需要扣除物品,在进入的时候已经判断过是否有物品了，这里直接扣除
					{
						RemoveDupItem(pGroupCfg);
					}
				}			

			} // end of if (!pDuplicate->OnceEnter(cid))

			//更新副本组数据
			UpdateDuplicate(protoUpdate);
		}
		else
		{
			//LogErrFmtPrint("[logic] DuplicatePart::PrepareEnter ... nullptr == pGroupCfg...groupID:%u,cid:%lu ", pCfg->groupID, cid);
		}
	}

	Duplicate_EnterRsp rsp;
	OnDupEnterRsp(enterParam, rsp);

	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
}

//重连
void DuplicatePart::NotifyReconnect(DupEnterParam &enterParam)
{
	Duplicate_EnterRsp rsp;
	OnDupEnterRsp(enterParam, rsp);
	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
}
//副本结束
void DuplicatePart::DuplicateFinish(DuplicateResult &result)
{
	Duplicate_ResultRsp rsp;
	rsp.set_duplicate_id(result.nDuplicateID);
	rsp.set_result(result.nResult);
	rsp.set_win_camp(result.byWinCamp);
	if (RET_SUCCESS == result.nResult)
	{
		const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(result.nDuplicateID);
		if (nullptr != pcfg)
		{
			Duplicate_UpdateRsp protoUpdate;
			//更新副本数据
			SET_UINT32::iterator iter = m_setAllDuplicate.find(result.nDuplicateID);
			if (iter == m_setAllDuplicate.end())
			{
				m_setAllDuplicate.insert(result.nDuplicateID);
			}
			//更新开启列表
			SET_UINT32::iterator iterOpen = m_setOpenDup.find(result.nDuplicateID);
			if (iterOpen != m_setOpenDup.end())
			{
				m_setOpenDup.erase(iterOpen);
			}


			DuplicateMap::iterator iterMap = m_mapDuplicate.find(result.nDuplicateID);
			if (iterMap == m_mapDuplicate.end())
			{
				SDuplicate stLevel;
				stLevel.nDuplicateID = result.nDuplicateID;
				m_mapDuplicate[stLevel.nDuplicateID] = stLevel;
				DuplicateSingleProto *protoDuplicate = protoUpdate.add_info();
				if (nullptr != protoDuplicate)
				{
					protoDuplicate->set_dupliate_id(stLevel.nDuplicateID);
				}
			}

			if ((int32_t)EDuplicateType::EDuplicateType_Ladder == pcfg->duplicateType)
			{
				const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pcfg->groupID);
				if (nullptr != pGroupCfg)
				{
					SDuplicateGroup *pGroup = GetGroup(pcfg->groupID);
					if (nullptr != pGroup)
					{
						if (nullptr != pGroup && pGroup->enterNum > 0)
						{
							pGroup->enterNum -= 1;  //天梯副本如果胜利了，归还副本次数,这里只是归还次数，不能设置进入时间
							DuplicateGroupProto *protoGroup = protoUpdate.add_group();
							if (nullptr != protoGroup)
							{
								protoGroup->set_group_id(pGroup->groupId);
								protoGroup->set_enter_num(pGroup->enterNum);
								protoGroup->set_use_item_num(pGroup->useItemNum);
								protoGroup->set_last_fresh(pGroup->lastFresh);
							}
						}
					} // enf of if (nullptr != pGroup)
				} // end of if (nullptr != pGroupCfg)
				
				//更新历史层数
				int32_t newLayer = g_GetDuplicateCfgMgr()->GetLadderLayerByDup(pcfg->duplicateID);
				if (newLayer > 0)
				{
					m_curLayer = newLayer;
					m_lastLayerTime = g_GetGlobalServerTime()->UnixSec();
					if (m_curLayer > m_historyLayer)
					{
						m_historyLayer = newLayer;
						//这里需要通知到中心服，更新中心服全服历史层数
						Player *pPlayer = static_cast<Player*>(m_pMaster);
						LogicToCenter_DuplicateLadderLayer notifyLayer;
						notifyLayer.set_name(pPlayer->GetName());
						notifyLayer.set_layer(m_historyLayer);					
						if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_LADDER_HISTORY_LAYER, &notifyLayer))
						{
							LogErrFmtPrint("[logic] DuplicatePart::DuplicateFinish....SendDataToCenter failed...cid:%lu , layer:%u ", pPlayer->GetCid(), m_historyLayer);
						}
					}
				}
				//更新天梯
				UpdateLadder();
			
			}
			else if ((int32_t)EDuplicateType::EDuplicateType_Cloud == pcfg->duplicateType)
			{
				DupCloudResultProto *protocloud = rsp.mutable_cloud();
				if (nullptr != protocloud)
				{

					protocloud->set_union_score(result.unionScore);			//工会积分
					protocloud->set_union_bossnum(result.unionBossNum);			//工会击杀boss数量
					protocloud->set_union_bossscore(result.unionBossScore);			//工会boss积分
					protocloud->set_union_normalnum(result.unionNormalNum);			//工会击杀小怪数量
					protocloud->set_union_normalscore(result.unionNormalScore);		//工会小怪积分
					protocloud->set_char_score(result.charScore);				//玩家积分
					protocloud->set_char_bossnum(result.charBossNum);			//玩家击杀boss数量
					protocloud->set_char_bossscore(result.charBossScore);			//玩家击杀boss积分
					protocloud->set_char_normalnum(result.charNormalNum);			//玩家击杀小怪数量
					protocloud->set_char_normalscore(result.charNormalScore);		//玩家击杀小怪积分
					protocloud->set_leftsec(result.leftsec);				//剩余时间
					protocloud->set_leftsecscore(result.leftsecScore);			//剩余时间积分
				}
			}
			
			//更新副本数据
			UpdateDuplicate(protoUpdate);
			//发送副本通关事件
			PassDupEvent passEvent;
			passEvent.dupId = result.nDuplicateID;
			passEvent.byTeam = result.byTeam;
			passEvent.groupId = pcfg->groupID;
			passEvent.isLadder = ((int32_t)EDuplicateType::EDuplicateType_Ladder == pcfg->duplicateType);
			passEvent.layer = m_curLayer;
			g_GetEvent()->FireExecute(EVENT_PASS_DUPLICATE, m_pMaster->GetCid(), m_pMaster->CreatureKind(), &passEvent, sizeof(PassDupEvent));

			//剧情副本活跃度是通关副本的时候才加的
			if ((int32_t)EDuplicateType::EDuplicateType_Story == pcfg->duplicateType)
			{
				//增加活跃度				HuoYueDuPart* pHuoYueDuPart = dynamic_cast<HuoYueDuPart*>(m_pMaster->GetPart(PART_HUOYUEDU));				if (nullptr != pHuoYueDuPart)				{					pHuoYueDuPart->AddHuoYueDuRecord(HYDT_STORY_DUP);				}
			}
			
			//
			LogDebugFmtPrint("[logic] DuplicatePart::DuplicateFinish....dupid:%u, charid:%lu ", result.nDuplicateID, m_pMaster->GetCid());

		} // end of if (nullptr != pcfg)
	} // end of if (RET_SUCCESS == result.nResult)

	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE,LOGIC_TO_CLIENT_DUPLICATE_RESULT,&rsp);
}

void DuplicatePart::CheckDupGroup()
{
	uint64_t curTime = g_GetGlobalServerTime()->UnixSec();
	DuplicateGroupMap::iterator iterGroup = m_mapGroup.begin();
	while (iterGroup != m_mapGroup.end())
	{
		SDuplicateGroup &stGroup = iterGroup->second;
		const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(stGroup.groupId);
		if (nullptr == pGroupCfg)
		{
			LogWarningFmtPrint("[logic] DuplicatePart::CheckDupGroup...nullptr == pGroupCfg....groupid:%u ", stGroup.groupId);
			iterGroup = m_mapGroup.erase(iterGroup);
			continue;
		}
		bool bfresh = false;
		if (EDupFreshType_Day == pGroupCfg->refreshType)
		{
			//检查上次刷新和这次登录是否是同一天
			if (TimeUtility::CheckDayUpdate(curTime,stGroup.lastFresh))
			{
				bfresh = true;				
			}
		}
		else if (EDupFreshType_Week == pGroupCfg->refreshType)
		{
			if (TimeUtility::CheckWeekUpdate(curTime, stGroup.lastFresh)) //检查上次刷新和这次登录是否是同一周
			{
				bfresh = true;
			}
		}
		if (bfresh)
		{
			stGroup.enterNum = 0;
			stGroup.useItemNum = 0;
			stGroup.lastFresh = curTime;
		}
		//
		++iterGroup;
	}

	//检查上次刷新和这次登录是否是同一天
	if (TimeUtility::CheckDayUpdate(curTime, m_lastLayerTime))
	{
		m_curLayer = 0;
		m_lastLayerTime = curTime;
		//
		const ConstantConstantCfgInfo *pConstCfg = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg_LadderDupResetCount);
		if (nullptr != pConstCfg)
		{
			m_curLayer = (pConstCfg->constantdata > m_historyLayer) ? 0 : (m_historyLayer - pConstCfg->constantdata);
			m_curLayer = (m_curLayer >= 1) ? (m_curLayer - 1) : 0;
		}
	}
}


//////////////////////////////////////////////////////////////////////////
//副本信息
void DuplicatePart::Info(const char *data, uint32_t len)
{
	Duplicate_InfoRsp ret;
	ret.set_retcode(RET_SUCCESS);
	DuplicateMap::iterator iter = m_mapDuplicate.begin();
	for (; iter != m_mapDuplicate.end(); ++iter)
	{
		SDuplicate &level = iter->second;
		const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(level.nDuplicateID);
		if (nullptr != pcfg && (int32_t)EDuplicateType::EDuplicateType_Ladder != pcfg->duplicateType)
		{
			DuplicateSingleProto *proto = ret.add_info();
			if (nullptr != proto)
			{
				proto->set_dupliate_id(level.nDuplicateID);
			}
		}
	}

	DuplicateGroupMap::iterator iterGroup = m_mapGroup.begin();
	for (; iterGroup != m_mapGroup.end(); ++iterGroup)
	{
		SDuplicateGroup &stGroup = iterGroup->second;
		DuplicateGroupProto *proto = ret.add_group();
		if (nullptr != proto)
		{
			proto->set_group_id(stGroup.groupId);
			proto->set_enter_num(stGroup.enterNum);
			proto->set_use_item_num(stGroup.useItemNum);
			proto->set_last_fresh(stGroup.lastFresh);
			//LogDebugFmtPrint("DuplicatePart::Info....groupid:%u, enternum:%d, usenum:%d, lastfresh:%lu ", stGroup.groupId, stGroup.enterNum, stGroup.useItemNum, stGroup.lastFresh);
		}
	}

	SET_UINT32::iterator iterOpen = m_setOpenDup.begin();
	for (; iterOpen != m_setOpenDup.end(); ++iterOpen)
	{
		ret.add_open_list((*iterOpen));
	}

	//设置可挑战的天梯副本信息
	DupLadderProto *protoLadder = ret.mutable_ladder();
	if (nullptr != protoLadder)
	{
		SetNextLayerInfo(protoLadder);
	}

	//全服天梯层数
	const GlobalDataProto &globalProto = g_GetLGlobalMgr()->GetGlobalData();
	if (globalProto.has_layer())
	{
		ret.set_serv_layer(globalProto.layer());
	}
	if (globalProto.has_name())
	{
		ret.set_serv_name(globalProto.name());
	}

	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_INFO, &ret);
}
//进入副本
void DuplicatePart::Enter(const char *data, uint32_t len)
{
	Duplicate_EnterReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_EnterReq parse failed...");
		return;
	}
	uint32_t nDuplicateID = req.duplicate_id();
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(nDuplicateID);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pCfg...nDuplicateID:%u ",nDuplicateID);
		return;
	}
	const MapMapCfgInfo *pMapCfg = g_GetMapMapCfgTable()->GetMapMapCfgInfo(pCfg->sceneResource);
	if (nullptr == pMapCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pMapCfg...nDuplicateID:%u, sceneResource:%u  ", nDuplicateID, pCfg->sceneResource);
		return;
	}
	const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pCfg->groupID);
	if (nullptr == pGroupCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pGroupCfg.. groupId:%u, nDuplicateID:%u ", pCfg->groupID, nDuplicateID);
		return;
	}
	uint32_t areaId = 0;
	Point3<float> pos = m_pMaster->GetPos();
	//int32_t continueFlag = 0;
	if (req.has_area_id())
	{
		areaId = req.area_id();
	}
	if (req.has_cur_pos())
	{
		const Vector3PB &vecProto = req.cur_pos();
		pos.x = vecProto.x();
		pos.y = vecProto.y();
		pos.z = vecProto.z();
	}
	/*if (req.has_flag())
	{
		continueFlag = req.flag();
	}*/
	Duplicate_EnterRsp rsp;
	rsp.set_retcode(RET_FAIL);
	if ((int32_t)EDuplicateType::EDuplicateType_New == pCfg->duplicateType)
	{
		int32_t ret = CanEnterNew(areaId, pos,pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (RET_SUCCESS == ret)
		{
			LogicToCenter_EnterDupReq reqCenter;
			reqCenter.set_charid(m_pMaster->GetCid());
			reqCenter.set_duplicate_id(nDuplicateID);
			reqCenter.set_key_type(EDuplicateKeyType_Single);
			reqCenter.set_key_value(m_pMaster->GetCid());
			DupBeforAreaProto *proto = reqCenter.add_area();
			if (nullptr != proto)
			{
				proto->set_charid(m_pMaster->GetCid());
				proto->set_areaid(areaId);
			}
			if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
			{
				LogErrFmtPrint("[logic] DuplicatePart::Enter new ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
			}
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Story == pCfg->duplicateType)
	{
		//剧情副本
		int32_t ret = CanEnterStory(areaId, pos, pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (ret == RET_SUCCESS)
		{
			if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
			{
				//如果有组队的话，队伍人数在中心服验证
				rsp.set_retcode(RET_FAIL);
			}
			else
			{
				//单人进入直接请求创建副本场景
				LogicToCenter_EnterDupReq reqCenter;
				reqCenter.set_charid(m_pMaster->GetCid());
				reqCenter.set_duplicate_id(nDuplicateID);
				reqCenter.set_key_type(EDuplicateKeyType_Single);
				reqCenter.set_key_value(m_pMaster->GetCid());
				DupBeforAreaProto *proto = reqCenter.add_area();
				if (nullptr != proto)
				{
					proto->set_charid(m_pMaster->GetCid());
					proto->set_areaid(areaId);
				}
				if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
				{
					LogErrFmtPrint("[logic] DuplicatePart::Enter story ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
				}
			}
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_SingleA == pCfg->duplicateType)
	{
		int32_t ret = CanEnterSingleA(pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (ret == RET_SUCCESS)
		{
			//单人进入直接请求创建副本场景
			LogicToCenter_EnterDupReq reqCenter;
			reqCenter.set_charid(m_pMaster->GetCid());
			reqCenter.set_duplicate_id(nDuplicateID);
			reqCenter.set_key_type(EDuplicateKeyType_Single);
			reqCenter.set_key_value(m_pMaster->GetCid());
			if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
			{
				LogErrFmtPrint("[logic] DuplicatePart::Enter sacta ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
			}
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Ladder == pCfg->duplicateType)
	{
		int32_t ret = CanEnterLadder(pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (ret == RET_SUCCESS)
		{
			/*if (continueFlag) //继续下一层挑战
			{
				Player *pPlayer = static_cast<Player*>(m_pMaster);
				uint32_t sceneId = pPlayer->GetSceneId();
				IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(sceneId);
				if (nullptr == pDuplicate)
				{
					ret = RET_DUPLICATE_NOT_IN_DUPLICATE;
				}
				else
				{
					ret = pDuplicate->Continue(pPlayer->GetCid());
				}
			}*/
			if (ret == RET_SUCCESS)
			{
				//单人进入直接请求创建副本场景
				LogicToCenter_EnterDupReq reqCenter;
				reqCenter.set_charid(m_pMaster->GetCid());
				reqCenter.set_duplicate_id(nDuplicateID);
				reqCenter.set_key_type(EDuplicateKeyType_Single);
				reqCenter.set_key_value(m_pMaster->GetCid());
				//reqCenter.set_flag(continueFlag);
				if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
				{
					LogErrFmtPrint("[logic] DuplicatePart::Enter ladder ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
				}
			}
			else
			{
				rsp.set_retcode(ret);
				m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
			}			
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Tower == pCfg->duplicateType)
	{
		int32_t ret = CanEnterTower(pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (ret == RET_SUCCESS)
		{
			LogicToCenter_EnterDupReq reqCenter;
			reqCenter.set_charid(m_pMaster->GetCid());
			reqCenter.set_duplicate_id(nDuplicateID);
			reqCenter.set_key_type(EDuplicateKeyType_Room);
			reqCenter.set_key_value((uint64_t)m_pMaster->GetAttr(C_ROOM_ID));
			if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
			{
				LogErrFmtPrint("[logic] DuplicatePart::Enter tower ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
			}
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}

	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Guard == pCfg->duplicateType)
	{
		int32_t ret = CanEnterGuard(pCfg, pGroupCfg);
		rsp.set_retcode(ret);
		if (ret == RET_SUCCESS)
		{
			LogicToCenter_EnterDupReq reqCenter;
			reqCenter.set_charid(m_pMaster->GetCid());
			reqCenter.set_duplicate_id(nDuplicateID);
			reqCenter.set_key_type(EDuplicateKeyType_Room);
			reqCenter.set_key_value((uint64_t)m_pMaster->GetAttr(C_ROOM_ID));
			if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_ENTER_DUP_REQ, &reqCenter))
			{
				LogErrFmtPrint("[logic] DuplicatePart::Enter guard ...SendDataToCenter failed...charid:%lu, nDuplicateID:%u ", m_pMaster->GetCid(), nDuplicateID);
			}
		}
		else
		{
			m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
		}
	}
	else
	{
		m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
	}
}

//离开副本
void DuplicatePart::Leave(const char *data, uint32_t len)
{
	uint32_t nDuplicateID = m_pMaster->GetAttr(C_DUPLICATE_ID);
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(nDuplicateID);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Leave ... nullptr == pCfg...nDuplicateID:%u ", nDuplicateID);
		return;
	}
	uint32_t nSceneID = m_pMaster->GetSceneId();
	Scene *pScene = g_GetSceneMgr()->GetScene(nSceneID);
	if (nullptr == pScene)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Leave ... nullptr == pScene...nSceneID:%u ", nSceneID);
		return;
	}
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(nSceneID);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Leave ... nullptr == pDuplicate...nSceneID:%u ", nSceneID);
		return;
	}
	Player *pPlayer = static_cast<Player*>(m_pMaster);
	Duplicate_LeaveRsp rsp;
	LogDebugFmtPrint("[logic] DuplicatePart::Leave....cid:%lu ,dupid:%u, sceneid:%u,hp:%ld ", m_pMaster->GetCid(),nDuplicateID,nSceneID,m_pMaster->GetAttr(C_HP));
	int32_t ret = pDuplicate->LeaveDuplicate(pPlayer);
	if (RET_SUCCESS != ret)
	{
		rsp.set_retcode(ret);
		m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_LEAVE, &rsp);
	}	
}

//复活
void DuplicatePart::Relive(const char *data, uint32_t len)
{
	Duplicate_ReliveReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_ReliveReq parse failed...");
		return;
	}

	uint32_t nDuplicateID = m_pMaster->GetAttr(C_DUPLICATE_ID);
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(nDuplicateID);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Relive ... nullptr == pCfg...nDuplicateID:%u ", nDuplicateID);
		return;
	}
	uint32_t nSceneID = m_pMaster->GetSceneId();
	Scene *pScene = g_GetSceneMgr()->GetScene(nSceneID);
	if (nullptr == pScene)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Relive ... nullptr == pScene...nSceneID:%u ", nSceneID);
		return;
	}
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(nSceneID);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("[logic] DuplicatePart::Relive ... nullptr == pDuplicate...nSceneID:%u ", nSceneID);
		return;
	}
	Duplicate_ReliveRsp rsp;
	rsp.set_retcode(RET_SUCCESS);
	Player *pPlayer = static_cast<Player*>(m_pMaster);
	if (!pPlayer->IsDead())
	{
		//为死亡RET_DUPLICATE_RELIVE_NO_DEAD
		rsp.set_retcode(RET_DUPLICATE_RELIVE_NO_DEAD);
	}
	else if (!pDuplicate->CanRelive(m_pMaster->GetCid()))
	{
		//不能复活
		rsp.set_retcode(RET_DUPLICATE_CAN_NOT_RELIVE);
	}
	else
	{
		/*副本复活取消扣除金币
		const ConstantConstantCfgInfo *pConstCfg = nullptr;
		if (byType == (int8_t)EDuplicateRelive::EDuplicateRelive_Money)
		{
			if (pDuplicate->PlayerReliveNum(pPlayer->GetCid()) >= pCfg->reviveMaxTimes)
			{
				//已经达到复活上限
				rsp.set_retcode(RET_DUPLICATE_RELIVE_NUM_LIMIT);
			}
			else
			{
				pConstCfg = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg_DupReliveDiamond);
				if (nullptr == pConstCfg)
				{
					LogErrFmtPrint("[logic] DuplicatePart::Relive....nullptr == pConstCfg....id:%u ", EArg_DupReliveDiamond);
					return;
				}
				if (pPlayer->GetAttr(C_GOLD) < (int64_t)pConstCfg->constantdata)
				{
					rsp.set_retcode(RET_GOLD_LACK);
				}
			}
		}*/
		if (RET_SUCCESS == rsp.retcode())
		{
			if (pDuplicate->Relive(pPlayer))
			{
				rsp.set_retcode(RET_SUCCESS);

			/*	if (byType == (int8_t)EDuplicateRelive::EDuplicateRelive_Money && nullptr != pConstCfg)
				{
					pPlayer->AddAttr(C_GOLD, -1*(int64_t)pConstCfg->constantdata, true);
				}*/

			}
			else
			{
				rsp.set_retcode(RET_FAIL);
			}
		}
	}
	
	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_RELIVE, &rsp);
}

//进入区域
void DuplicatePart::EnterArea(const char *data, uint32_t len)
{
	Duplicate_EnterAreaReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_EnterAreaReq parse failed...");
		return;
	}
	uint32_t nDuplicateID = m_pMaster->GetAttr(C_DUPLICATE_ID);
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(nDuplicateID);
	if (nullptr == pCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::EnterArea ... nullptr == pCfg...nDuplicateID:%u ", nDuplicateID);
		return;
	}
	uint32_t nSceneID = m_pMaster->GetSceneId();
	Scene *pScene = g_GetSceneMgr()->GetScene(nSceneID);
	if (nullptr == pScene)
	{
		LogErrFmtPrint("[logic] DuplicatePart::EnterArea ... nullptr == pScene...nSceneID:%u ", nSceneID);
		return;
	}
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(nSceneID);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("[logic] DuplicatePart::EnterArea ... nullptr == pDuplicate...nSceneID:%u ", nSceneID);
		return;
	}
	//
	Duplicate_EnterAreaRsp rsp;
	rsp.set_retcode(RET_FAIL);
	uint32_t nAreaID = req.area_id();

	//这里校验区域配置和角色当前的位置



	if (pDuplicate->EnterArea(nAreaID))
	{
		rsp.set_retcode(RET_SUCCESS);
	}
	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER_AREA, &rsp);
}

//更新副本开启
void DuplicatePart::UpdateDupOpen(SET_UINT32 &setAdd)
{
	if (setAdd.size() > 0)
	{
		Duplicate_UpdateRsp update;
		SET_UINT32::iterator iter = m_setOpenDup.begin();
		for (; iter != m_setOpenDup.end(); ++iter)
		{
			update.add_open_list((*iter));
		}
		UpdateDuplicate(update);
	}	
}
//更新天梯
void DuplicatePart::UpdateLadder()
{
	Duplicate_LadderUpdate update;
	DupLadderProto *protoLadder = update.mutable_ladder_update();
	if (nullptr != protoLadder)
	{
		SetNextLayerInfo(protoLadder);
	}
	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_LADDER_UPDATE, &update);
}

//设置下一个挑战层副本信息
void DuplicatePart::SetNextLayerInfo(DupLadderProto *protoLadder)
{
	if (nullptr != protoLadder)
	{
		int32_t next_layer = m_curLayer + 1;
		uint32_t nextDupId = g_GetDuplicateCfgMgr()->GetLadderDupByLalyer(next_layer);

		protoLadder->set_history_layer(m_historyLayer);
		DuplicateSingleProto *proto = protoLadder->mutable_dup();
		if (nullptr != proto)
		{
			proto->set_dupliate_id(nextDupId);
		}		
	}
}

//邀请进入副本
void DuplicatePart::InviteEnter(const char *data, uint32_t len)
{
	Duplicate_InviteReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_InviteReq parse failed....");
		return;
	}
	uint32_t dupId = req.dupid();
	uint32_t areaId = req.area_id();
	const Vector3PB &pos = req.cur_pos();
	Point3<float> curpos(pos.x(), pos.y(), pos.z());
	const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pcfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::InviteEnter.....nullptr == pcfg  dupid:%u ", dupId);
		return;
	}
	const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pcfg->groupID);
	int32_t ret = RET_SUCCESS;
	if ((int32_t)EDuplicateType::EDuplicateType_Story == pcfg->duplicateType)
	{
		if (nullptr == pGroupCfg)
		{
			LogErrFmtPrint("[logic] DuplicatePart::InviteEnter.....nullptr == pGroupCfg  dupid:%u , groupid:%u ", dupId, pcfg->groupID);
			return;
		}

		ret = CanEnterStory(areaId, curpos, pcfg, pGroupCfg);
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Pestilence == pcfg->duplicateType)
	{
		ret = CanEnter(pcfg, pGroupCfg);
	}
	else
	{
		ret = RET_FAIL;
	}
	
	if (RET_SUCCESS != ret)
	{
		Duplicate_InviteRsp rsp;
		rsp.set_retcode(ret);
		m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_INVITE_ENTER, &rsp);
	}
	else
	{
		LogicToCenter_DupliateInivteReq inviteReq;
		inviteReq.set_char_id(m_pMaster->GetCid());
		inviteReq.set_dupid(dupId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_INVITE_ENTER, &inviteReq);
	}
}
//回复邀请
void DuplicatePart::ReplyInvite(const char *data, uint32_t len)
{
	Duplicate_ReplyInviteReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_ReplyInviteReq parse failed....");
		return;
	}
	uint32_t dupId = req.dupid();
	int32_t reply = req.reply();
	if (EDupTeamCharState_Agree != reply && EDupTeamCharState_Refuse != reply)
	{
		return;
	}
	const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pcfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::ReplyInvite.....nullptr == pcfg  dupid:%u ", dupId);
		return;
	}
	const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pcfg->groupID);
	if ((int32_t)EDuplicateType::EDuplicateType_Story == pcfg->duplicateType)
	{
		//LogErrFmtPrint("[logic] DuplicatePart::ReplyInvite.....EDuplicateType::EDuplicateType_Story != pcfg->duplicateType  dupid:%u , type:%d ", dupId, pcfg->duplicateType);
		if (nullptr == pGroupCfg)
		{
			LogErrFmtPrint("[logic] DuplicatePart::ReplyInvite.....nullptr == pGroupCfg  dupid:%u , groupid:%u ", dupId, pcfg->groupID);
			return;
		}
	}
	else if ((int32_t)EDuplicateType::EDuplicateType_Pestilence == pcfg->duplicateType)
	{
	}
	else
	{
		LogErrFmtPrint("[logic] DuplicatePart::ReplyInvite.....duplicate type can not reply....   dupid:%u , type:%d ", dupId, pcfg->duplicateType);
		return;
	}
	int32_t ret = CanEnter(pcfg, pGroupCfg);
	if (RET_SUCCESS == ret)
	{
		if (m_pMaster->GetAttr(C_TEAM_ID) <= 0)
		{
			ret = RET_TEAM_NO_TEAM;
		}
		else if (m_pMaster->GetAttr(C_TEAM_LEADER_ID))
		{
			ret = RET_DUPLICATE_TEAM_LEADER_REPLY;
		}
	}
	if (RET_SUCCESS != ret)
	{
		Duplicate_ReplyInviteRsp rsp;
		rsp.set_retcode(ret);
		m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_REPLY_INVITE, &rsp);

		if (EDupTeamCharState_Agree == reply) //同意进入副本的时候，进入失败才需要通知队员
		{
			if (RET_LEVEL_LACK == ret || RET_DUPLICATE_LACK_ENTER_NUM == ret)
			{
				//等级不足和次数不足的时候需要通知其他队员
				LCDupReplyFailResonReq notify;
				notify.set_char_id(m_pMaster->GetCid());
				notify.set_dupid(dupId);
				notify.set_reason(ret);
				g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_REPLY_FAILD_REASON, &notify);
			}
		}		
	}
	else
	{
		LogicToCenter_DuplicateReplyReq replyReq;
		replyReq.set_char_id(m_pMaster->GetCid());
		replyReq.set_reply(reply);
		replyReq.set_dupid(dupId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_INVITE_REPLY, &replyReq);
	}

}

//开始挑战（竞技场）
void DuplicatePart::StartChallenge(const char *data, uint32_t len)
{
	_UNUSE(data);
	_UNUSE(len);
	Duplicate_StartChallengeRsp rsp;
	uint32_t sceneId = m_pMaster->GetSceneId();
	int32_t ret = RET_FAIL;
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(sceneId);
	if (nullptr != pDuplicate)
	{
		ret = pDuplicate->StartChallenge(m_pMaster->GetCid());

	}
	else
	{
		ret = RET_DUPLICATE_NOT_IN_DUPLICATE;
	}
	rsp.set_retcode(ret);
	m_pMaster->SendDataToClientEx(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_START_CHALLENGE, &rsp);
}

//掉落数据
void DuplicatePart::DropData(const char *data, uint32_t len)
{
	uint32_t sceneId = m_pMaster->GetSceneId();
	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(sceneId);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("DuplicatePart::DropData...cid:%lu,sceneid:%u ", m_pMaster->GetCid(), sceneId);
		return;
	}
	Duplicate_DropRsp rsp;
	DupAllDropProto *proto = rsp.mutable_info();
	if (nullptr == proto)
	{
		LogErrFmtPrint("DuplicatePart::DropData...nullptr == proto cid:%lu,sceneid:%u,dup:%u ", m_pMaster->GetCid(), sceneId, pDuplicate->GetDuplicateID());
		return;
	}
	pDuplicate->SetDropData(*proto);
	//
	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_DROP_DATA, &rsp);
}

//加入排队
void DuplicatePart::JoinQueue(const char *data, uint32_t len)
{
	//瘟疫活动去掉了，暂时先注释
	/*Duplicate_JoinQueueReq req;
	if (!req.ParseFromArray(data,len))
	{
		LogErrFmtPrint("[logic] Duplicate_JoinQueueReq parse failed...");
		return;
	}
	int32_t actId = g_GetDuplicateCfgMgr()->GetPestilenceActId();
	const ActivityDailyCfgInfo *pActivityCfg = g_GetActivityDailyCfgTable()->GetActivityDailyCfgInfo(actId);
	if (nullptr == pActivityCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::JoinQueue....nullptr == pActivityCfg...actId:%d ", actId);
		return;
	}
	uint32_t pestilenceDupId = g_GetDuplicateCfgMgr()->GetPestilenceDupId();
	const DuplicateDuplicateCfgInfo *pDupCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(pestilenceDupId);
	if (nullptr == pDupCfg)
	{
		LogErrFmtPrint("[logic] DuplicatePart::JoinQueue....nullptr == pDupCfg...pestilenceDupId:%u ", pestilenceDupId);
		return;
	}
	const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pDupCfg->groupID);
	int32_t ret = CanEnter(pDupCfg, pGroupCfg);
	if (RET_SUCCESS == ret)
	{
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0) //这里是单人加入排队，队伍的从队长邀请进副本那边
		{
			ret = RET_DUPLICATE_IN_TEAM;
		}

		if (RET_SUCCESS == ret)
		{
			//通知中心服加入队列
			LCDupJoinQueueReq centerReq;
			centerReq.set_char_id(m_pMaster->GetCid());
			g_GetLogicService()->SendDataToCenter(EMODULE_ID_DUPLICATE, LOGIC_TO_CENTER_DUPLICATE_JOIN_QUEUE, &centerReq);
			return;
		}
	}
	//
	Duplicate_JoinQueueRsp rsp;
	rsp.set_retcode(ret);
	m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_JOIN_QUEUE, &rsp);*/
}

//更新副本
void DuplicatePart::UpdateDuplicate(Duplicate_UpdateRsp &update)
{
	if (update.info_size() > 0 || update.group_size() > 0 || update.open_list_size() > 0)
	{
		m_pMaster->SendDataToClient(EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_UPDATE, &update);
	}	
}


//////////////////////////////////////////////////////////////////////////


//获取副本组
SDuplicateGroup *DuplicatePart::GetGroup(uint32_t groupId)
{
	DuplicateGroupMap::iterator iter = m_mapGroup.find(groupId);
	return (iter != m_mapGroup.end()) ? &iter->second : nullptr;
}
//获取副本
SDuplicate *DuplicatePart::GetDuplicate(uint32_t duplicateId)
{
	DuplicateMap::iterator iter = m_mapDuplicate.find(duplicateId);
	return (iter != m_mapDuplicate.end()) ? &iter->second : nullptr;
}


//是否能进副本(副本房间专用)
int32_t DuplicatePart::CanEnterDup(uint32_t dupId)
{
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pCfg)
	{
		//LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pCfg...nDuplicateID:%u ", dupId);
		return RET_FAIL;
	}
	const MapMapCfgInfo *pMapCfg = g_GetMapMapCfgTable()->GetMapMapCfgInfo(pCfg->sceneResource);
	if (nullptr == pMapCfg)
	{
		//LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pMapCfg...nDuplicateID:%u, sceneResource:%u  ", dupId, pCfg->sceneResource);
		return RET_FAIL;
	}
	const DuplicateGroupCfgInfo *pGroupCfg = g_GetDuplicateGroupCfgTable()->GetDuplicateGroupCfgInfo(pCfg->groupID);
	/*if (nullptr == pGroupCfg)
	{
		//LogErrFmtPrint("[logic] DuplicatePart::Enter ... nullptr == pGroupCfg.. groupId:%u, nDuplicateID:%u ", pCfg->groupID, dupId);
		return RET_FAIL;
	}*/
	return CanEnter(pCfg, pGroupCfg);
}

//进入副本返回的数据
bool DuplicatePart::OnDupEnterRsp(DupEnterParam &enterParam, Duplicate_EnterRsp &rsp)
{
	CharIDType cid = m_pMaster->GetCid();
	uint32_t nDuplicateID = enterParam.dupId;
	uint32_t nSceneID = enterParam.sceneId;
	int8_t keyType = enterParam.keyType;
	MAP_UINT64_UINT64 &mapOutPut = enterParam.mapPlayerOutput;
	MAP_UINT64_UINT64 &mapBear = enterParam.mapPlayerBear;
	MAP_UINT32_INT32 &mapMonsDie = enterParam.mapMonsDieNum;
	MAP_UINT32_INT32 &mapMonsTotal = enterParam.mapMonsTotalNum;

	IDuplicate *pDuplicate = g_GetDuplicateMgr()->GetDuplicate(nSceneID);
	if (nullptr == pDuplicate)
	{
		LogErrFmtPrint("[logic] DuplicatePart::OnReconnect...can not find duplicate ....cid:%lu, dupid:%u, nSceneID:%u ", cid, nDuplicateID, nSceneID);
		return false;
	}

	uint64_t towerCurHp = 0;
	uint64_t towerMaxHp = 0;
	int32_t transNum = pDuplicate->GetTransNum();
	int32_t exploitNum = pDuplicate->GetExploit(cid);
	rsp.set_retcode(RET_SUCCESS);
	rsp.set_duplicate_id(nDuplicateID);
	rsp.set_mons_num(pDuplicate->GetMonsterNum());
	rsp.set_dup_sec(pDuplicate->LeftSec());

	pDuplicate->GetTowerInfo(towerCurHp, towerMaxHp);
	rsp.set_tower_hp(towerCurHp);
	rsp.set_tower_max_hp(towerMaxHp);
	rsp.set_trans_num(transNum);
	rsp.set_exploit(exploitNum);
	rsp.set_dup_flag(keyType);
	rsp.set_cur_time(g_GetGlobalServerTime()->UnixSec());

	//战斗数据
	if (EDuplicateKeyType_Room == keyType
		|| EDuplicateKeyType_Team == keyType)
	{
		MAP_UINT64_UINT64::iterator iterOuput = mapOutPut.begin();
		for (; iterOuput != mapOutPut.end(); ++iterOuput)
		{
			CharIDType cid = iterOuput->first;
			CharIDType output = iterOuput->second;
			CharIDType bear = 0;
			//
			MAP_UINT64_UINT64::iterator iterBear = mapBear.find(cid);
			if (iterBear != mapBear.end())
			{
				bear = iterBear->second;
			}

			DupFightDataProto *protoFight = rsp.add_fight_data();
			if (nullptr != protoFight)
			{
				protoFight->set_cid(cid);
				protoFight->set_atk(output);
				protoFight->set_be_atk(bear);
			}
		}
	}
	else if (EDuplicateKeyType_Pestilence == keyType)
	{
		int32_t contisec = 0;
		int32_t injectTransId = 0;
		int32_t surviveTransId = 0;
		int8_t camp = pDuplicate->GetDupCharCamp(cid);		;
		pDuplicate->GetPestilenceContiAndTransID(contisec, injectTransId, surviveTransId);
		rsp.set_camp(camp);
		rsp.set_conti_sec(contisec);
		rsp.set_inject_transid(injectTransId);
		rsp.set_survive_transid(surviveTransId);
	}

	//云端试炼结束时间
	if (enterParam.cloudEndTime > 0)
	{
		rsp.set_cloud_end_time(enterParam.cloudEndTime);
	}
	//云端试练当前波数信息
	if (enterParam.curWave > 0)
	{
		DupCloudWaveProto *protoWave = rsp.mutable_wave_info();
		if (nullptr != protoWave)
		{
			protoWave->set_wave(enterParam.curWave);
			protoWave->set_mons_die(enterParam.monsDie);
			protoWave->set_total_mons(enterParam.totalMons);
			SET_UINT32::iterator iterBoss = enterParam.setBoss.begin();
			for (; iterBoss != enterParam.setBoss.end(); ++iterBoss)
			{
				protoWave->add_boss_lst((*iterBoss));
			}
		}
	}
	//boss状态
	if (enterParam.mapBossState.size() > 0)
	{
		DupAllMonsStateProto *allproto = rsp.mutable_boss_state();
		if (nullptr != allproto)
		{
			MAP_UINT32_INT8::iterator iterState = enterParam.mapBossState.begin();
			for (; iterState != enterParam.mapBossState.end(); ++iterState)
			{
				DupMonsStateProto *proto = allproto->add_all_state();
				if (nullptr != proto)
				{
					proto->set_mons_id(iterState->first);
					proto->set_state(iterState->second);
				}
			}
		}
	}
	//阻挡
	MAP_UINT32_INT8 mapBlockState;
	mapBlockState.clear();
	pDuplicate->GetBlockState(mapBlockState);
	DupAllBlockStateProto *protoAllBlock = rsp.mutable_block();
	MAP_UINT32_INT8::iterator iterBlock = mapBlockState.begin();
	for (; iterBlock != mapBlockState.end(); ++iterBlock)
	{
		if (nullptr != protoAllBlock)
		{
			DupBlockStateProto *protoBlock = protoAllBlock->add_all_block();
			if (nullptr != protoBlock)
			{
				protoBlock->set_block_id(iterBlock->first);
				protoBlock->set_state(iterBlock->second);
			}
		}
	}

	//需要客户端检查的区域
	SET_UINT32 setArea;
	setArea.clear();
	AllBrushDataCfg *pAllBrush = pDuplicate->GetBrushData();
	if (nullptr != pAllBrush)
	{
		MAP_UINT32_VEC_UINT32::iterator iter = pAllBrush->stCommon.mapVecEnterArea.begin();
		for (; iter != pAllBrush->stCommon.mapVecEnterArea.end(); ++iter)
		{
			setArea.insert(iter->first);
		}
		//
		VecNewStepCfg::const_iterator iterStep = pAllBrush->stNew.vecNewStep.begin();
		for (; iterStep != pAllBrush->stNew.vecNewStep.end(); ++iterStep)
		{
			const NewStepCfgInfo &step = (*iterStep);
			MAP_UINT32_VEC_UINT32::const_iterator iterAreaStep = step.mapVecEnterArea.begin();
			for (; iterAreaStep != step.mapVecEnterArea.end(); ++iterAreaStep)
			{
				setArea.insert(iterAreaStep->first);
				//LogDebugFmtPrint("DuplicatePart::OnDupEnterRsp...brush mons..cid:%lu,areaid:%u ", m_pMaster->GetCid(), iterAreaStep->first);
			}
			MAP_UINT32_SET_UINT32::const_iterator iterAreaNpc = step.mapNpcEnterArea.begin();
			for (; iterAreaNpc != step.mapNpcEnterArea.end();++iterAreaNpc)
			{
				setArea.insert(iterAreaNpc->first);
				//LogDebugFmtPrint("DuplicatePart::OnDupEnterRsp...brush npc..cid:%lu,areaid:%u ", m_pMaster->GetCid(), iterAreaNpc->first);
			}
		}
	}
	//阻挡里面的区域
	AllBlockDataCfg *pAllBlock = pDuplicate->GetBlockCfg();
	if (nullptr != pAllBlock)
	{
		MAP_UINT32_SET_UINT32::iterator iter = pAllBlock->mapSetEnterArea.begin();
		for (; iter != pAllBlock->mapSetEnterArea.end(); ++iter)
		{
			setArea.insert(iter->first);
		}
	}
	SET_UINT32::iterator iterArea = setArea.begin();
	for (; iterArea != setArea.end(); ++iterArea)
	{
		rsp.add_area((*iterArea));
	}

	//副本怪物数量信息
	if (mapMonsDie.size() > 0)
	{
		DupAllMonsNumProto *protoAllMons = rsp.mutable_mons_lst();
		MAP_UINT32_INT32::iterator iterDie = mapMonsDie.begin();
		for (; iterDie != mapMonsDie.end(); ++iterDie)
		{
			DupMonsNumProto *proto = protoAllMons->add_info_lst();
			if (nullptr != proto)
			{
				proto->set_mons_id(iterDie->first);
				proto->set_die_num(iterDie->second);
				MAP_UINT32_INT32::iterator iterTotal = mapMonsTotal.find(iterDie->first);
				if (iterTotal != mapMonsTotal.end())
				{
					proto->set_total_num(iterTotal->second);
				}
			}
		}
	}

	return true;

}

//是否有进入副本需要的物品
bool DuplicatePart::HasDupItem(const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pGroupCfg || pGroupCfg->enterItemID <= 0)
	{
		return false;
	}
	Player *pPlayer = dynamic_cast<Player*>(m_pMaster);
	if (nullptr == pPlayer)
	{
		return false;
	}
	Part *pPackage = pPlayer->GetPart(PART_PACKAGE);
	if (nullptr == pPackage)
	{
		return false;
	}
	//是否有进入道具
	int32_t bindNum = 0;
	int32_t unbindNum = 0;
	return (pPackage->GetItemNum((uint32_t)pGroupCfg->enterItemID, unbindNum,bindNum) > 0);
}
//扣除进入副本需要的物品
bool DuplicatePart::RemoveDupItem(const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pGroupCfg)
	{
		return false;
	}
	Player *pPlayer = dynamic_cast<Player*>(m_pMaster);
	if (nullptr == pPlayer)
	{
		return false;
	}
	Part *pPackage = pPlayer->GetPart(PART_PACKAGE);
	if (nullptr == pPackage)
	{
		return false;
	}
	//移除物品
	SItemSourceParam sourceParam;
	sourceParam.source = S_Dup;
	return pPackage->RemoveItem((uint32_t)pGroupCfg->enterItemID, 1, sourceParam);
}


int32_t DuplicatePart::CanEnter(int8_t keyType, uint64_t keyValue, const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}

	if (EDuplicateKeyType_Single == keyType)
	{
		if (m_pMaster->GetCid() != (uint32_t)keyValue)
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
	}
	else if (EDuplicateKeyType_Team == keyType)
	{
		if ((int32_t)m_pMaster->GetAttr(C_TEAM_ID) != (int32_t)keyValue)
		{
			return RET_DUPLICATE_IN_ERROR_TEAM;
		}
	}
	else if (EDuplicateKeyType_Room == keyType)
	{
		if ((int32_t)m_pMaster->GetAttr(C_ROOM_ID) != (int32_t)keyValue)
		{
			return RET_DUPLICATE_IN_ERROR_ROOM;
		}
	}

	return RET_SUCCESS;
}
//能否进入副本
int32_t DuplicatePart::CanEnter(const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg /*|| nullptr == pGroupCfg*/)
	{
		return RET_FAIL;
	}
	if (!g_GetMapLocationCfg()->RandBornLocation(pCfg->sceneResource))
	{
		return RET_FAIL;
	}
	//已死亡
	if (m_pMaster->IsDead())
	{
		return RET_DUPLICATE_ALREDY_DEAD;
	}
	//等级
	if ((int32_t)m_pMaster->GetAttr(C_LEVEL) < pCfg->levelLimit)
	{
		return RET_LEVEL_LACK;
	}
	//进入次数
	if (nullptr != pGroupCfg)
	{
		if (DUP_INFINITE_ENTER_NUM != pGroupCfg->groupTimes) 
		{
			SDuplicateGroup *pGroup = GetGroup(pGroupCfg->id);
			if (nullptr != pGroup)
			{
				if (pGroup->enterNum >= pGroupCfg->groupTimes)//超过免费次数，就需要扣除道具进入副本
				{
					if (!HasDupItem(pGroupCfg))
					{
						return RET_DUPLICATE_LACK_ENTER_NUM;
					}
				}
			}
			else if (0 == pGroupCfg->groupTimes) //副本组配置成0次，表示没有免费次数
			{
				if (!HasDupItem(pGroupCfg))
				{
					return RET_DUPLICATE_LACK_ENTER_NUM;
				}
			}
		}		
	}
	//前置副本
	if (pCfg->linkDuplicateRequest > 0)
	{
		SET_UINT32::iterator iterPre = m_setAllDuplicate.find(pCfg->linkDuplicateRequest);
		if (iterPre == m_setAllDuplicate.end())
		{
			return RET_DUPLICATE_PRE_NOT_PASS;
		}
	}

	
	uint32_t unlockTaskId = g_GetDuplicateCfgMgr()->GetDuplicateUnlockTask((int8_t)m_pMaster->GetAttr(C_RACE),(uint32_t)pCfg->duplicateID);
	if (unlockTaskId > 0)
	{
		//解锁任务是否完成
		MissionPart *pMissionPart = (MissionPart*)m_pMaster->GetPart(PART_MISSION);
		if (nullptr == pMissionPart)
		{
			return RET_DUPLICATE_IS_UNLOCK;
		}
		if (!pMissionPart->HaveFinish(unlockTaskId)) //这里需要判断是否解锁任务
		{
			return RET_DUPLICATE_IS_UNLOCK;
		}
	}
	
	//副本组解锁等级
	if (nullptr != pGroupCfg)
	{
		if ((int32_t)m_pMaster->GetAttr(C_LEVEL) < pGroupCfg->unlockLevel)
		{
			return RET_LEVEL_LACK;
		}
	}

	int32_t actId = 0;
	PLAYER_ROLE_STATIS_TYPE_E opType = PRSTE_TEST;	
	if ((int8_t)EDuplicateType::EDuplicateType_New == pCfg->duplicateType)
	{
		//不能组队，不能在房间
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
		{
			return RET_DUPLICATE_IN_TEAM;
		}
		if (m_pMaster->GetAttr(C_ROOM_ID) > 0)
		{
			return RET_DUPLICATE_IN_ROOM;
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Story == pCfg->duplicateType)
	{
		//不能再房间
		if (m_pMaster->GetAttr(C_ROOM_ID) > 0)
		{
			return RET_DUPLICATE_IN_ROOM;
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Tower == pCfg->duplicateType)
	{
		//不能组队
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
		{
			return RET_DUPLICATE_IN_TEAM;
		}
		actId = g_GetDuplicateCfgMgr()->GetTowerActId();
		opType = PRSTE_TOWER;
	/*	//必须在房间
		if (m_pMaster->GetAttr(C_ROOM_ID) <= 0)
		{
			return RET_DUPLICATE_NOT_IN_ROOM;
		}*/
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Guard == pCfg->duplicateType)
	{
		//不能组队
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
		{
			return RET_DUPLICATE_IN_TEAM;
		}
		actId = g_GetDuplicateCfgMgr()->GetGuardActId();
		opType = PRSTE_GUARD;
	/*	//必须在房间
		if (m_pMaster->GetAttr(C_ROOM_ID) <= 0)
		{
			return RET_DUPLICATE_NOT_IN_ROOM;
		}*/
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_SingleA == pCfg->duplicateType)
	{
		//不能组队
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
		{
			return RET_DUPLICATE_IN_TEAM;
		}

		//不能再房间
		if (m_pMaster->GetAttr(C_ROOM_ID) > 0)
		{
			return RET_DUPLICATE_IN_ROOM;
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Ladder == pCfg->duplicateType)
	{
		//不能组队
		if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
		{
			return RET_DUPLICATE_IN_TEAM;
		}

		//不能再房间
		if (m_pMaster->GetAttr(C_ROOM_ID) > 0)
		{
			return RET_DUPLICATE_IN_ROOM;
		}
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Pestilence == pCfg->duplicateType)
	{
		actId = g_GetDuplicateCfgMgr()->GetPestilenceActId();
		opType = PRSTE_PESTILENCE;
	}
	else if ((int8_t)EDuplicateType::EDuplicateType_Cloud == pCfg->duplicateType)
	{
		//远端试炼 工会活动只能在工会驻地接取
		uint32_t mapId = m_pMaster->GetMapId();
		const Map *pMap = g_GetMapMgr()->GetMap(mapId);
		if (nullptr != pMap)
		{
			if (!pMap->IsUnion())
			{
				//不在工会驻地
				return RET_ACTIVITY_NOT_IN_UNION_HOME_SCENE;
			}
		}
		actId = g_GetDuplicateCfgMgr()->GetCloudActId();
		opType = PRSTE_CLOUD;
	}

	//活动副本 需要判断活动次数
	if (PRSTE_TEST != opType)
	{
		const ActivityDailyCfgInfo *pActivityCfg = g_GetActivityDailyCfgTable()->GetActivityDailyCfgInfo(actId);
		if (nullptr != pActivityCfg)
		{
			if (!g_GetGActivityMgr()->IsRunning(pActivityCfg->activeId))
			{
				return RET_ACTIVITY_NOT_OPEN;
			}
			if (pActivityCfg->totalNum > 0)
			{
				OperateLimit *pOperatePart = dynamic_cast<OperateLimit*>(m_pMaster->GetPart(PART_OPERATELIMIT));
				if (nullptr != pOperatePart && (int32_t)pOperatePart->GetLimitCount(opType) >= pActivityCfg->totalNum)
				{
					return RET_ACTIVITY_NUM_LIMIT;
				}
			}
		}		
	}
	

	return RET_SUCCESS;
}
//能否进入新手副本
int32_t DuplicatePart::CanEnterNew(uint32_t areaId, Point3<float>pos, const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}
	uint32_t mapId = m_pMaster->GetMapId();
	if (!g_GetMapLocationCfg()->GetAreaRefLoc(mapId, areaId))
	{
		return RET_DUPLICATE_AREA_NOT_EXIST;
	}
	Scene *pScene = m_pMaster->GetScene();
	if (nullptr == pScene)
	{
		return RET_FAIL;
	}
	//不在区域内
	if (!pScene->InArea(areaId, pos))
	{
		return RET_DUPLICATE_AREA_NOT_EXIST;
	}
	VEC_INT32 vecArea;
	CommonApi::SplitStrToVecInt(pCfg->trigEntry, ",", &vecArea);
	VEC_INT32::iterator iter = std::find(vecArea.begin(), vecArea.end(), areaId);
	if (iter == vecArea.end())
	{
		return RET_DUPLICATE_ENTER_AREA;
	}

	return RET_SUCCESS;
}
//能否进入剧情副本
int32_t DuplicatePart::CanEnterStory(uint32_t areaId, Point3<float>pos, const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}

	//如果在队伍中，是否是队长
	if (m_pMaster->GetAttr(C_TEAM_ID) > 0)
	{
		if (!m_pMaster->GetAttr(C_TEAM_LEADER_ID))
		{
			return RET_DUPLICATE_NOT_TEM_LEADER;
		}
	}
	uint32_t mapId = m_pMaster->GetMapId();
	if (!g_GetMapLocationCfg()->GetAreaRefLoc(mapId, areaId))
	{
		return RET_DUPLICATE_AREA_NOT_EXIST;
	}
	Scene *pScene = m_pMaster->GetScene();
	if (nullptr == pScene)
	{
		return RET_FAIL;
	}
	//不在区域内
	if (!pScene->InArea(areaId, pos))
	{
		return RET_DUPLICATE_ENTER_AREA;
	}

	

	return RET_SUCCESS;
}

//是否能进入塔防副本
int32_t DuplicatePart::CanEnterTower(const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}
	if (m_pMaster->GetAttr(C_ROOM_ID) <= 0)
	{
		return RET_ROOM_NOT_JOIN;
	}
	if (!m_pMaster->GetAttr(C_ROOM_LEADER_ID))
	{
		return RET_ROOM_NOT_OWNER;
	}

	return RET_SUCCESS;
}
//是否能进入守护副本
int32_t DuplicatePart::CanEnterGuard(const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}
	if (m_pMaster->GetAttr(C_ROOM_ID) <= 0)
	{
		return RET_ROOM_NOT_JOIN;
	}
	if (!m_pMaster->GetAttr(C_ROOM_LEADER_ID))
	{
		return RET_ROOM_NOT_OWNER;
	}

	return RET_SUCCESS;
}

//是否能进入单人活动副本
int32_t DuplicatePart::CanEnterSingleA(const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}

	return RET_SUCCESS;
}


//能否进入天梯副本
int32_t DuplicatePart::CanEnterLadder(const DuplicateDuplicateCfgInfo *pCfg, const DuplicateGroupCfgInfo *pGroupCfg)
{
	if (nullptr == pCfg || nullptr == pGroupCfg)
	{
		return RET_FAIL;
	}
	int32_t ret = CanEnter(pCfg, pGroupCfg);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}
	int32_t layer = g_GetDuplicateCfgMgr()->GetLadderLayerByDup(pCfg->duplicateID);
	if (layer <= 0)
	{
		return RET_DUPLICATE_CAN_NOT_ENTER;
	}
	if (layer <= m_curLayer)
	{
		return RET_DUPLICATE_ALREADY_PASS;
	}

	return RET_SUCCESS;
}


//////////////////////////////////////////////////////////////////////////
